<?php

/** Framework_Controller_Exception */
require_once 'Framework/Controller/Exception.php';

/** Framework_Controller_Plugin_Abstract */
require_once 'Framework/Controller/Plugin/Abstract.php';

/** Framework_Controller_Request_Abstract */
require_once 'Framework/Controller/Request/Abstract.php';

/** Framework_Controller_Response_Abstract */
require_once 'Framework/Controller/Response/Abstract.php';

class Framework_Controller_Plugin_Broker extends Framework_Controller_Plugin_Abstract
{
    /**
     * Массив инстанцированных объектов расширяющих Framework_Controller_Plugin_Abstract
     *
     * @var array
     */
    protected $_plugins = array();

    /**
     * Регистрация плагина
     *
     * @param  Framework_Controller_Plugin_Abstract $plugin
     * @param  int $stackIndex
     * @return Framework_Controller_Plugin_Broker
     */
    public function registerPlugin(Framework_Controller_Plugin_Abstract $plugin)
    {
        if (false !== array_search($plugin, $this->_plugins, true)) {
            throw new Framework_Controller_Exception('Plugin already registered');
        }
        $stackIndex = count($this->_plugins);
        $this->_plugins[$stackIndex] = $plugin;

        $request = $this->getRequest();
        if ($request) {
            $this->_plugins[$stackIndex]->setRequest($request);
        }
        $response = $this->getResponse();
        if ($response) {
            $this->_plugins[$stackIndex]->setResponse($response);
        }

        return $this;
    }

    /**
     * Set request object, and register with each plugin
     *
     * @param Framework_Controller_Request_Abstract $request
     * @return Framework_Controller_Plugin_Broker
     */
    public function setRequest(Framework_Controller_Request_Abstract $request)
    {
        $this->_request = $request;

        foreach ($this->_plugins as $plugin) {
            $plugin->setRequest($request);
        }

        return $this;
    }

    /**
     * Get request object
     *
     * @return Framework_Controller_Request_Abstract $request
     */
    public function getRequest()
    {
        return $this->_request;
    }

    /**
     * Set response object
     *
     * @param Framework_Controller_Response_Abstract $response
     * @return Framework_Controller_Plugin_Broker
     */
    public function setResponse(Framework_Controller_Response_Abstract $response)
    {
        $this->_response = $response;

        foreach ($this->_plugins as $plugin) {
            $plugin->setResponse($response);
        }


        return $this;
    }

    /**
     * Get response object
     *
     * @return Framework_Controller_Response_Abstract $response
     */
    public function getResponse()
    {
        return $this->_response;
    }

    /**
     * Called before Framework_Controller_Front begins evaluating the
     * request against its routes.
     *
     * @param Framework_Controller_Request_Abstract $request
     * @return void
     */
    public function routeStartup(Framework_Controller_Request_Abstract $request)
    {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->routeStartup($request);
            } catch (Exception $e) {
                if (Framework_Controller_Front::getInstance()->throwExceptions()) {
                    throw $e;
                } else {
                    $this->getResponse()->setException($e);
                }
            }
        }
    }

    /**
     * Called before Framework_Controller_Front exits its iterations over
     * the route set.
     *
     * @param  Framework_Controller_Request_Abstract $request
     * @return void
     */
    public function routeShutdown(Framework_Controller_Request_Abstract $request)
    {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->routeShutdown($request);
            } catch (Exception $e) {
                if (Framework_Controller_Front::getInstance()->throwExceptions()) {
                    throw $e;
                } else {
                    $this->getResponse()->setException($e);
                }
            }
        }
    }
}
